﻿using log4net.Appender;
using log4net.Config;
using log4net.Layout;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CPPEI
{
    public static class Logger
    {
        private static string s_logOutputDirectory;
        private static Dictionary<string, log4net.ILog> s_loggerDict = new Dictionary<string, log4net.ILog>();
        private static IAppender s_allAppender;

        private static readonly string TAG_ALL = "ALL";
        private static object s_lockObj = new object();
        private const string LogFormatString = "%d\t[%t]\t%p\t%logger\t%m%newline";
        private static bool s_hasInit = false;

        /// <summary>
        /// 获得log4net的日志器
        /// </summary>
        /// <param name="tag"></param>
        /// <returns></returns>
        private static log4net.ILog GetLog(string tag)
        {
            if (s_loggerDict.ContainsKey(tag))
            {
                return s_loggerDict[tag];
            }
            else
            {
                if (string.IsNullOrEmpty(s_logOutputDirectory))
                {
                    return null;
                }
                lock (s_lockObj)
                {
                    if (s_loggerDict.ContainsKey(tag))
                    {
                        return s_loggerDict[tag];
                    }
                    log4net.ILog log = log4net.LogManager.GetLogger(tag);
                    log4net.Repository.Hierarchy.Logger logger = (log4net.Repository.Hierarchy.Logger)log.Logger;
                    logger.Level = logger.Hierarchy.LevelMap[TAG_ALL];
                    //if (tag != TAG_ALL)
                    //{
                    //    logger.AddAppender(s_allAppender);
                    //}
                    if (!string.Equals(tag, TAG_ALL))
                    {
                        logger.AddAppender(GetRollingFileAppender(s_logOutputDirectory, tag));
                    }
                    //logger.AddAppender(GetConsoleAppender(tag));
                    s_loggerDict.Add(tag, log);
                    return log;
                }
            }
        }

        /// <summary>
        /// 初始化日志接口，加载log4net的配置文件
        /// </summary>
        /// <param name="configFile"></param>
//        [Obsolete("暂不使用")]
//        public static void Init(string configFile)
//        {
//            FileInfo fileinfo = new FileInfo(configFile);
//            log4net.Config.XmlConfigurator.Configure(fileinfo);
//#if DEBUG
//            System.Diagnostics.Debug.WriteLine(string.Format("{0}\t{1}", "Init", configFile));
//#endif
//        }

        /// <summary>
        /// 根据日志路径初始化
        /// </summary>
        /// <param name="directory">日志存储目录，需要绝对路径</param>
        public static void InitByLogDirectory(string directory)
        {
            if (!s_hasInit)
            {
                s_logOutputDirectory = directory;

                BasicConfigurator.Configure(GetConsoleAppender());
                BasicConfigurator.Configure(GetRollingFileAppender(s_logOutputDirectory, TAG_ALL));

                //s_allAppender = GetRollingFileAppender(s_logOutputDirectory, TAG_ALL);
                s_hasInit = true;
            }
            else
            {
                throw new Exception("log组件已经初始化，不能重复初始化");
            }
        }

        /// <summary>
        /// 使用文本记录异常日志
        /// </summary>
        /// <Author>zyzheng</Author>
        /// <date>2014-4-16</date>
        private static RollingFileAppender GetRollingFileAppender(string logDirectory, string tag)
        {
            if(string.IsNullOrEmpty(logDirectory))
            {
                return null;
            }
            /*
             *   <param name="File" value="Logs\\Error\\" /><!-- 输出到什么目录-->
                <param name="AppendToFile" value="true" /><!-- 是否覆写到文件中-->
                <!--<param name="MaxSizeRollBackups" value="100" />--><!-- 备份文件的个数-->
                <!--<param name="MaxFileSize" value="10240" />--><!-- 单个日志文件最大的大小-->
                <param name="StaticLogFileName" value="false" /><!-- 是否使用静态文件名-->
                <param name="DatePattern" value="yyyy-MM-dd&quot;.log&quot;" /><!-- 日志文件名-->
                <param name="RollingStyle" value="Date" />
                <layout type="log4net.Layout.PatternLayout">
                  <param name="ConversionPattern" value="%d  [%t] %p  %m %newline"  />
                </layout>
             */
            string txtLogPath = string.Empty;
            txtLogPath = Path.Combine(logDirectory, tag + "\\");

            RollingFileAppender fileAppender = new RollingFileAppender();
            fileAppender.Name = string.Format("{0}Appender", tag);
            fileAppender.File = string.Format("{0}{1}\\", logDirectory, tag);
            fileAppender.AppendToFile = true;
            fileAppender.StaticLogFileName = false;
            fileAppender.DatePattern = "yyyy-MM-dd\".log\"";
            fileAppender.RollingStyle = RollingFileAppender.RollingMode.Date;

            PatternLayout patternLayout = new PatternLayout();
            patternLayout.ConversionPattern = LogFormatString;
            patternLayout.ActivateOptions();
            fileAppender.Layout = patternLayout;

            //选择UTF8编码，确保中文不乱码。
            fileAppender.Encoding = Encoding.UTF8;

            fileAppender.ActivateOptions();
            return fileAppender;
        }

        private static ConsoleAppender GetConsoleAppender()
        {
            ConsoleAppender appender = new ConsoleAppender();
            appender.Name = "ConsoleAppender";

            PatternLayout patternLayout = new PatternLayout();
            patternLayout.ConversionPattern = LogFormatString;
            patternLayout.ActivateOptions();
            appender.Layout = patternLayout;

            appender.ActivateOptions();
            return appender;
        }

        #region info
        public static void Info(string message)
        {
            InfoToTag(TAG_ALL, message);
        }

        public static void Info(string messageFormat, params object[] args)
        {
            Info(string.Format(messageFormat, args));
        }

        /// <summary>
        /// 信息日志
        /// </summary>
        /// <param name="tag">获取信息Logger的名字</param>
        /// <param name="message">信息消息</param>
        public static void InfoToTag(string tag, string message)
        {
            log4net.ILog loginfo = GetLog(tag);
            if (loginfo == null)
            {
                return;
            }
            loginfo.Info(message);
        }

        /// <summary>
        /// 数组调用信息日志方法
        /// </summary>
        /// <param name="tag">获取信息Logger的名字</param>
        /// <param name="messageFormat"></param>
        /// <param name="args">数组</param>
        public static void InfoToTag(string tag, string messageFormat, params object[] args)
        {
            InfoToTag(tag, string.Format(messageFormat, args));
        }

        #endregion

        #region debug
        public static void Debug(string message)
        {
            DebugToTag(TAG_ALL, message);
        }

        public static void Debug(string messageFormat, params object[] args)
        {
            Debug(string.Format(messageFormat, args));
        }

        /// <summary>
        /// 输出日志
        /// </summary>
        /// <param name="tag">标签名称</param>
        /// <param name="message">输出信息</param>
        public static void DebugToTag(string tag, string message)
        {
            log4net.ILog logdebug = GetLog(tag);
            if (logdebug == null)
            {
                return;
            }
            logdebug.Debug(message);
        }

        /// <summary>
        /// 数组调用输出日志方法
        /// </summary>
        /// <param name="tag">标签名称</param>
        /// <param name="messageFormat"></param>
        /// <param name="args">数组</param>
        public static void DebugToTag(string tag, string messageFormat, params object[] args)
        {
            DebugToTag(tag, string.Format(messageFormat, args));
        }

        #endregion

        #region warning
        public static void Warning(string message)
        {
            WarningToTag(TAG_ALL, message);
        }

        public static void Warning(string messageFormat, params object[] args)
        {
            WarningToTag(TAG_ALL, string.Format(messageFormat, args));
        }

        /// <summary>
        /// 警告日志
        /// </summary>
        /// <param name="tag">标签名称</param>
        /// <param name="message">警告信息</param>
        public static void WarningToTag(string tag, string message)
        {
            log4net.ILog logwarning = GetLog(tag);
            if (logwarning == null)
            {
                return;
            }
            //Console.ForegroundColor = ConsoleColor.Yellow;
            logwarning.Warn(message);
            //Console.ForegroundColor = ConsoleColor.White;
        }

        /// <summary>
        /// 数组调用警告日志的方法
        /// </summary>
        /// <param name="tag">标签名称</param>
        /// <param name="messageFormat"></param>
        /// <param name="args">数组</param>
        public static void WarningToTag(string tag, string messageFormat, params object[] args)
        {
            WarningToTag(tag, string.Format(messageFormat, args));
        }

        #endregion

        #region error
        public static void Error(string message)
        {
            ErrorToTag(TAG_ALL, message);
        }

        public static void Error(string messageFormat, params object[] args)
        {
            ErrorToTag(TAG_ALL, messageFormat, args);
        }

        /// <summary>
        /// 错误日志
        /// </summary>
        /// <param name="tag">标签名称</param>
        /// <param name="message">错误消息</param>
        public static void ErrorToTag(string tag, string message)
        {
            log4net.ILog logerror = GetLog(tag);
            if (logerror == null)
            {
                return;
            }
            //Console.ForegroundColor = ConsoleColor.Red;
            logerror.Error(message);
            //Console.ForegroundColor = ConsoleColor.White;
        }

        /// <summary>
        /// 数组调用错误日志方法
        /// </summary>
        /// <param name="tag">标签名称</param>
        /// <param name="messageFormat"></param>
        /// <param name="args">数组</param>
        public static void ErrorToTag(string tag, string messageFormat, params object[] args)
        {
            ErrorToTag(tag, string.Format(messageFormat, args));
        }

        #endregion
        #region FATAL

        /// <summary>
        /// 致命错误,
        /// </summary>
        /// <param name="message">错误内容</param>
        public static void Fatal(string message)
        {
            FatalToTag(TAG_ALL, message);
        }

        /// <summary>
        /// 致命错误,
        /// </summary>
        /// <param name="messageFormat"></param>
        /// <param name="args"></param>
        public static void Fatal(string messageFormat, params object[] args)
        {
            FatalToTag(TAG_ALL, messageFormat, args);
        }

        /// <summary>
        /// 致命错误,
        /// </summary>
        /// <param name="tag">标签名称</param>
        /// <param name="message">错误消息</param>
        public static void FatalToTag(string tag, string message)
        {
            log4net.ILog logerror = GetLog(tag);
            if (logerror == null)
            {
                return;
            }
            //Console.ForegroundColor = ConsoleColor.Red;
            logerror.Fatal(message);
            //Console.ForegroundColor = ConsoleColor.White;
        }

        /// <summary>
        /// 致命错误,
        /// </summary>
        /// <param name="tag">标签名称</param>
        /// <param name="messageFormat"></param>
        /// <param name="args">参数</param>
        public static void FatalToTag(string tag, string messageFormat, params object[] args)
        {
            FatalToTag(tag, string.Format(messageFormat, args));
        }

        #endregion
    }
}
